#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <assert.h>
#include <errno.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/dir.h>
#include <sys/stat.h>

#include "bstrlib.h"
#include "server.h"
#include "fd_list.h"
#include "common.h"
#include "receive.h"
#include "send_file_listing.h"
#include "send_metadata.h"
#include "send_slice.h"


int send_msg(int fd_client, char *msg){
    /*Esta funcion la utilizamos para las respuestas desde al cliente*/
    int aux_send = 0, length = 0, i=0, finished=0;
    char *aux_msg = NULL;
    assert (msg != NULL);
    assert (fd_client != 0);

    length = strlen(msg);

    while(finished == 0){
        #ifdef __DEBUG__
        printf("send_msg %s\n", msg);
        #endif
        aux_send = send(fd_client, msg, length, 0);
        if (aux_send == -1){
            perror("send");
            if (errno==ECONNRESET || errno==EPIPE || errno==ESPIPE){
                return -1;
            }
            return 0;
        }
        if (aux_send == length){
                finished = 1;
        }
        else{
            aux_msg = calloc(length,sizeof(char*));
            for (i=aux_send; i<length; i++){
                aux_msg[i-aux_send]=msg[i];
            }
            strncpy(msg, aux_msg, aux_send);
            length = strlen(msg);
            free(aux_msg);
            aux_msg = NULL;
        }
    }
    return 0;
}

int attend_hello(fd_list list, int i){
    if(fd_list_is_first_time(list, i)){
        /*Si es la primera vez que entra, acepto el hello
        marco el cliente como ya visitado, le envio confirmacion de
        recepcion de su hello y lo marco como que ya no necesito
        hacerle mas nada*/
        #ifdef __DEBUG__
        printf("Recibi hello de un cliente y es su primer comando\n");
        #endif
        fd_list_item_visited(list, i);
        send_msg(fd_list_get_fd(list, i), MSG0);
        fd_list_set_finish(list, i, true);
        return 1;
    }
    else{
        /*si entra aca es porque no nos mandó un hello como primer
        comando*/
        #ifdef __DEBUG__
        printf("Recibi hello de un cliente pero NO es su primer comando\n");
        #endif
        return 0;
    }
}

int send_hello(fd_list list, int i, int global_port){
    int fd=0;
    char *port;

    port = calloc(7, sizeof(char*));
    fd = fd_list_get_server_fd(list, i);

    if(send_msg(fd, "hello ")!=0)
        return -1;

    sprintf(port, "%i",global_port);

    if(send_msg(fd, port)!=0)
        return -1;
    if(send_msg(fd, "\r\n")!=0)
        return -1;

    free(port);
    port = NULL;
    return 1;

}

int connect_to_server(fd_list list, int j){
    int s=0, port=0, result=0, connection=0, i=0, already_connected=0,\
    aux_fd=0, server_port=0;
    struct sockaddr_in sa, sb;
    socklen_t sa_len, sb_len;

    sa_len = sizeof(struct sockaddr);
    sb_len = sizeof(struct sockaddr);

    /*cargamos el fd del cliente para obtener su info*/
    aux_fd = fd_list_get_fd(list, j);
    if (getsockname(aux_fd, (struct sockaddr *)&sb, &sb_len) == -1) {
        perror("getsockname() failed");
        return -1;
    }
    port = fd_list_get_item_port(list, j);
    sb.sin_port = htons(port);

    /*iteramos sobre los servers que tenemos para ver si ya estamos
    conectados a el*/
    for (i=0;i<fd_list_server_size(list);i++){
        s=fd_list_get_server_fd(list, i);
        if (getsockname(s, (struct sockaddr *)&sa, &sa_len) == -1) {
            perror("getsockname() failed");
            return -1;
        }
        server_port = fd_list_get_server_port(list, i);

        if (sa.sin_addr.s_addr == sb.sin_addr.s_addr){
            if (port == server_port){
                already_connected=1;
                break;
            }
        }
    }

    if (already_connected!=1){
        /*Es un cliente que se conectó a nosotros, entonces tenemos que
        conectarnos de vuelta*/
        printf("Nos conectamos a: %s\n", inet_ntoa(sb.sin_addr));
        printf("Usando el puerto: %i\n", port);
        /*creo el socket*/
        result = socket(PF_INET, SOCK_STREAM, 0);
        if (result == -1) {
            printf("Error al crear el Socket\n");
            return -1;
        }
        /*si no hubo error, hago la conexion*/
        connection = connect(result, (struct sockaddr *)&sb,\
                                      sizeof(struct sockaddr));
        if (connection != 0) {
            printf("Error al intentar establecer la conexión\n");
            return -1;
        }
        /*Si pude conectarme, seteo la relacion entre
        el servidor y el cliente*/
        fd_list_add_server_fd(list, result);
        i = fd_list_server_search(list, result);
        fd_list_server_set_relation(list, i, aux_fd);
        fd_list_item_set_relation(list, j, result);
        /*informo que tengo que enviarle el hello*/
        fd_list_set_server_cmd(list, i, 5);
        fd_list_set_server_port(list, i, port);
        /*informo que tengo que seguir con este servidor*/
        fd_list_server_send(list, i);
        return result;
    }
    else{
        /*El cliente se acaba de conectar porque nosotros nos conectamos
        antes, no hace falta conectarnos, solo setear la relacion*/
        fd_list_server_set_relation(list, i, aux_fd);
        fd_list_item_set_relation(list, j, s);
        /*y marco que no tengo que hacer mas nada*/
        fd_list_set_finish(list, j, true);
        /*fd_list_server_not_send(list, i);*/
        return 0;
    }
}

int get_files(fd_list list, int i){
    int fd=0;
    fd = fd_list_get_server_fd(list, i);

    #ifdef __DEBUG__
    printf("Envio el get_file_listing al servidor\n");
    #endif
    if(send_msg(fd, "get_file_listing\r\n")!=0)
        return -1;

    return 1;
}

int load_files(fd_list list, int i){
    /*Esta funcion es usada para cargar en la estructura los nombres
    de archivo que estan en el servidor*/
    int fd_client=0, aux_recv=0, cur_size=0, j=0, h=0, counter=0;
    char *aux_buf=NULL, *server_recvd=NULL, *filename=NULL, *filename_temp=NULL;

    fd_client = fd_list_get_server_fd(list, i);
    aux_buf = calloc(BUF_LENGTH, sizeof(char*));
    if(aux_buf == NULL){
        perror("malloc-aux_buf");
        send_msg(fd_client, MSG199);
        close(fd_client);
        fd_list_remove(list, i);
        return -1;
    }
    /*Recibo del servidor el get_file_listing*/
    aux_recv = recv(fd_client, aux_buf, BUF_LENGTH, 0);
    if (aux_recv == -1){
        perror("recv");
    }
    if (aux_recv == 0){
        free(aux_buf);
        aux_buf=NULL;
        close(fd_client);
        fd_list_remove(list, i);
        return -1;
    }

    /*lo agrego a la estructura*/
    fd_list_add_server_recv_str(list, i, aux_buf, aux_recv);

    server_recvd = fd_list_get_server_recv_str(list, i);

    cur_size = strlen(server_recvd);
    /*Analizo que haya recibido todo*/
    for(j=0;j<cur_size;j++){
        if (server_recvd[j] == '\n'){
            if (server_recvd[j-1] == '\r' && server_recvd[j-2] == '\n'\
                && server_recvd[j-3] == '\r'){
                fd_list_reset_server_recv_str(list, i);
                fd_list_add_server_recv_str(list, i, server_recvd, j+1);
                fd_list_set_server_recv(list, i, true);
                break;
            }
            if (server_recvd[j-1] != '\r'){
                /*malformed*/
                return -1;
            }
        }
    }
    free(server_recvd);
    server_recvd = NULL;


    if (fd_list_get_server_recv(list, i)){
        /*Si entré a este if, es porque termine de recibir cosas del servidor
        debo parsear*/
        server_recvd = fd_list_get_server_recv_str(list, i);
        cur_size = strlen(server_recvd);
        counter = 0;
        h = 0;
        filename_temp = calloc(cur_size, sizeof(char));
        for(j=0;j<cur_size-2;j++){
            if (counter == 0 && j<4){
                if (server_recvd[j] == ' '){
                    if(strcmp(filename_temp, "0")!=0){
                        return -1;
                    }
                }
                filename_temp[h] = server_recvd[j];
                h++;
            }
            if (server_recvd[j] == '\r' && server_recvd[j+1] == '\n'){

                if (counter>0){
                    /*Obtuve el nombre de uno de los archivos, entonces
                    lo agrego a la estructura*/
                    filename = calloc(h+2, sizeof(char));
                    strncpy(filename, filename_temp, h);
                    fd_list_server_append_filename(list, i, filename);
                    free(filename);
                    filename=NULL;
                }
                counter++;
                j++;
                h=0;
            }
            else{
                if (counter>0){
                    filename_temp[h] = server_recvd[j];
                    h++;
                }
            }
        }
        free(filename_temp);
        filename_temp=NULL;
        free(server_recvd);
        server_recvd = NULL;
    }

    free(aux_buf);
    aux_buf=NULL;
    return 1;
}

int get_metadata(fd_list list, int i){
    int fd_client=0, count=0, j=0, msg_len=0, filename_len=0;
    char *filename=NULL, *msg=NULL, *other_filename=NULL;
    struct dirent **files;

    /*Tomo el fd del servidor y el nombre del primer archivo de mi lista
    de archivos tentativos*/
    fd_client = fd_list_get_server_fd(list, i);
    filename = fd_list_server_get_filename_from_list(list, i);

    /*Si no tengo archivos en la lista, entonces devuelvo 0*/
    if (fd_list_get_server_filenames_count(list, i) == 0){
        #ifdef __DEBUG__
        printf("Lista de archivos vacía\n");
        #endif

        return 0;
    }

    /*Examino todos los servidores buscando su primer archivo
    si lo encuentro en otro quiere decir que ese tambien esta listo
    para bajarlo o ya lo está haciendo, con lo cual llevo este al final
    de la cola para una posible descarga en caso que el otro se caiga*/
    for (j=0;j<fd_list_server_size(list);j++){
        if (j!=i){
            other_filename=fd_list_server_get_filename_from_list(list, j);
            if (other_filename != NULL &&\
                strcmp(filename, other_filename)==0){
                fd_list_server_swap_filename(list, i);
                #ifdef __DEBUG__
                printf("Estoy bajando %s de otro server, moviendo al final\n",\
                filename);
                #endif
                return 0;
            }
        }
    }

    /*Examino el directorio de archivos, si encuentro un archivo con el
    mismo nombre, quiere decir que ya lo bajé y que esta completo
    con lo cual debo eliminarlo de mi lista tentativa*/
    count = scandir(FOLDER, &files, 0, alphasort);

    for (j=2;j<count;j++){
        msg_len=strlen(files[j]->d_name);
        msg = calloc((msg_len+2), sizeof(char));
        strncpy(msg, files[j]->d_name, (msg_len+2));
        msg_len=strlen(msg);
        filename_len=strlen(filename);
        if(msg_len==filename_len){
            if (strncmp(msg, filename, msg_len)==0){
                #ifdef __DEBUG__
                printf("Ya tengo el archivo %s, eliminandolo de la lista\n",\
                filename);
                #endif
                fd_list_server_remove_filename_from_list(list, i);
                free(msg);
                msg=NULL;
                for (j=0; j<count; j++){
                        free(files[j]);
                    }
                    free(files);
                    files = NULL;
                return 0;
            }
        }
        free(msg);
        msg=NULL;
    }

    for (j=0; j<count; j++){
        free(files[j]);
    }
    free(files);
    files = NULL;

    /*en caso de llegar aca, es porque el archivo no lo tengo ni lo estoy
    bajando de otro lado, entonces pido el metadata*/
    send_msg(fd_client, "get_metadata ");
    send_msg(fd_client, filename);
    send_msg(fd_client, "\r\n");
    #ifdef __DEBUG__
    printf("Pedí el metadata para %s\n", filename);
    #endif
    return 1;
}

int load_metadata(fd_list list, int i){
    int fd_client=0, aux_recv=0, cur_size=0, j=0, h=0, counter=0, meta;
    char *aux_buf=NULL, *server_recvd=NULL, *metadata=NULL, \
         *metadata_temp=NULL, *end_ptr=NULL;

    /*Tomo el fd del servidor*/
    fd_client = fd_list_get_server_fd(list, i);
    aux_buf = calloc(BUF_LENGTH, sizeof(char*));
    if(aux_buf == NULL){
        perror("malloc-aux_buf");
        send_msg(fd_client, MSG199);
        close(fd_client);
        fd_list_remove(list, i);
        return -1;
    }
    /*recibo el metadata pedido*/
    aux_recv = recv(fd_client, aux_buf, BUF_LENGTH, 0);
    if (aux_recv == -1){
        perror("recv");
    }
    if (aux_recv == 0){
        free(aux_buf);
        aux_buf=NULL;
        close(fd_client);
        fd_list_remove(list, i);
        return -1;
    }

    /*lo cargo en la estructura en caso de no haber recibido todo
    para seguir recibiendo mas tarde*/
    fd_list_add_server_recv_str(list, i, aux_buf, aux_recv);

    server_recvd = fd_list_get_server_recv_str(list, i);

    cur_size = strlen(server_recvd);

    /*Utilizo counter para saber si estoy en la primer linea de lo recibido
    ie la linea del 0 OK\r\n.
    cuando counter == 1 estoy en la linea donde deberia tener el metadata del
    archivo
    una vez que corroboré que tengo el mensaje bien formado, termino con el
    break*/
    counter = 0;
    for(j=0;j<cur_size;j++){
        if (server_recvd[j] == '\n'){
            if (server_recvd[j-1] == '\r' && counter == 0){
                counter ++;
            }
            else if (server_recvd[j-1] == '\r' && counter == 1){
                fd_list_reset_server_recv_str(list, i);
                fd_list_add_server_recv_str(list, i, server_recvd, j+1);
                fd_list_set_server_recv(list, i, true);
                break;
            }
            if (server_recvd[j-1] != '\r'){
                /*malformed*/
                return -1;
            }
        }
    }
    free(server_recvd);
    server_recvd = NULL;


    if (fd_list_get_server_recv(list, i)){
        /*Si se mete a este IF es porque no tengo que recibir más nada
        y tengo que identificar donde se encuentra el valor metadata*/
        server_recvd = fd_list_get_server_recv_str(list, i);
        cur_size = strlen(server_recvd);
        counter = 0;
        h = 0;
        metadata_temp = calloc(cur_size, sizeof(char));
        for(j=0;j<cur_size;j++){
            if (counter == 0 && j<4){
                /*Si entro a este if, estoy analizando la primer parte del
                mensaje recibido, el cual debería comenzar con 0*/
                if (server_recvd[j] == ' '){
                    if(strcmp(metadata_temp, "0")!=0){
                        /*caso contrario, salgo con error*/
                        return -1;
                    }
                }
                /*en metadata_temp voy guardando el valor numerico del
                comienzo*/
                metadata_temp[h] = server_recvd[j];
                h++;
            }
            if (server_recvd[j] == '\r' && server_recvd[j+1] == '\n'){

                if (counter == 1){
                    /*Si entro aca, estoy analizando el metadata*/
                    metadata = calloc(h+2, sizeof(char));
                    /*en metadata_temp deberia tener el metadata
                    recibido*/
                    strncpy(metadata, metadata_temp, h);
                    meta = strtol(metadata, &end_ptr, 10);
                    if (end_ptr == metadata){
                        /*Si entro aca es porque no tengo un entero en donde
                        deberia haber recibido el metadata*/
                        send_msg(fd_client, MSG201);
                        free(metadata);
                        metadata=NULL;
                        free(metadata_temp);
                        metadata_temp=NULL;
                        free(server_recvd);
                        server_recvd = NULL;
                        free(aux_buf);
                        aux_buf=NULL;
                        return -1;
                    }
                    else{
                        /*Si es entero entra aqui, en donde lo cargo a la
                        estructura, y seteo el "transferred en 0*/
                        meta = (int)meta;
                        fd_list_server_set_metadata(list, i, meta);
                        fd_list_server_set_transferred(list, i, 0);
                    }
                    free(metadata);
                    metadata=NULL;
                }
                if (counter > 1){
                    /*Si entro aca es porque no recibi la respuesta del
                    metadata correctamente*/
                    free(metadata_temp);
                    metadata_temp=NULL;
                    free(server_recvd);
                    server_recvd = NULL;
                    free(aux_buf);
                    aux_buf=NULL;
                    return -1;
                }
                counter++;
                j++;
                h=0;
            }
            else{
                if (counter>0){
                    /*aca voy cargando el valor del metadata*/
                    metadata_temp[h] = server_recvd[j];
                    h++;
                }
            }
        }
        free(metadata_temp);
        metadata_temp=NULL;
        free(server_recvd);
        server_recvd = NULL;
    }

    free(aux_buf);
    aux_buf=NULL;
    return 1;
}

int get_slice(fd_list list, int i){
    int fd_client=0, metadata=0;
    char *filename=NULL, *meta=NULL;

    /*Tomo el fd del servidor, el archivo y su tamaño
    y armo el get_slice para mandar*/
    fd_client = fd_list_get_server_fd(list, i);
    filename = fd_list_server_get_filename_from_list(list, i);
    metadata = fd_list_server_get_metadata(list, i);
    if(send_msg(fd_client, "get_slice ")==-1){
        return 0;
    }
    if(send_msg(fd_client, filename)==-1){
        return 0;
    }
    if(send_msg(fd_client, " 0 ")==-1){
        return 0;
    }
    meta=calloc(40,sizeof(char));
    sprintf(meta, "%i",metadata);
    if(send_msg(fd_client, meta)==-1){
        free(meta);
        meta=NULL;
        return 0;
    }
    if(send_msg(fd_client, "\r\n")==-1){
        free(meta);
        meta=NULL;
        return 0;
    }

    free(meta);
    meta=NULL;
    return 1;
}

int get_file_from_server(fd_list list, int i){
    int fd_client=0, transferred=0, amount=0, q=0, p=0, h=0, not_loaded = 0,\
        aux_recv=0, should_end=0, num=0, sep_index=0, scan_buf=0;
    char *filename=NULL, *aux_buf=NULL, *file_temp=NULL,\
         *number=NULL, *end_ptr=NULL, *payload=NULL, *aux=NULL,\
         *aux_old=NULL, *aux_new=NULL;
    FILE *f = NULL;
    bstring received=NULL, sep=NULL;

    fd_client = fd_list_get_server_fd(list, i);
    filename = fd_list_server_get_filename_from_list(list, i);
    transferred = fd_list_server_get_transferred(list, i);
    amount = fd_list_server_get_metadata(list, i);

    /*Si llegué aca es porque efectivamente no tengo el archivo y debo bajarlo*/
    aux_buf = calloc(BUF_LENGTH, sizeof(char*));
    if(aux_buf == NULL){
        perror("malloc-aux_buf");
        send_msg(fd_client, MSG199);
        close(fd_client);
        fd_list_remove(list, i);
        return -1;
    }
    aux_recv = recv(fd_client, aux_buf, BUF_LENGTH, 0);
    if (aux_recv == -1){
        perror("recv");
    }
    if (aux_recv == 0){
        /*BORRAR EL ARCHIVO SI EXISTE EN TEMP_FOLDER*/
        #ifdef __DEBUG__
        printf("Perdi la conexion con el servidor, borrando el archivo\
 de la carpeta temporal\n");
        #endif
        aux = calloc (strlen(TEMP_FOLDER) + strlen(filename)+2,\
                    sizeof(char*));
        strcpy (aux,TEMP_FOLDER);
        strncat (aux, filename, strlen(filename));
        remove(aux);
        free(aux);
        aux=NULL;
        free(aux_buf);
        aux_buf=NULL;
        close(fd_client);
        fd_list_server_remove(list, i);
        return -1;
    }
    /*cargo en received lo que tengo en la estructura*/
    received = fd_list_server_get_file(list, i);
    if (received == NULL){
        printf("hola\n");
    }
    /*indico el separador*/
    sep = blk2bstr("\r\n", 2);
    /*concateno al bstring lo que recibi del server*/
    bcatblk(received, aux_buf, aux_recv);
    /*Ahora en received tengo lo que tenia más lo que recibi ahora*/

    
    sep_index = binstr(received,0,sep);
    if (sep_index != -1){
        scan_buf = 1;
    }

    h = 0;
    q = 0;
    file_temp=bstr2cstr(received,'\0');
    while (scan_buf){
        h = q;
        number = calloc(strlen(file_temp), sizeof(char));
        p=0;
        while (file_temp[h]!=' '){
            number[p] = file_temp[h];
            p++;
            h++;
        }
        h++;
        /*Cargo en num el tamaño del payload transferido*/
        num = strtol(number, &end_ptr, 10);
        if (end_ptr != number){
            num = (int)num;
            free(number);
            number=NULL;
        }
        else{
            /*Si entra aca es porque el mensaje no viene de la forma
            int(espacio)payload*/
            printf("El primer elemento recibido no es entero\n");
            free(number);
            number=NULL;
            bcstrfree(file_temp);
            file_temp = NULL;
            free(aux_buf);
            aux_buf=NULL;
            return -1;
        }

        if (num == 0 && (sep_index - h) == 0){
            /*Si estoy aca, estoy viendo el 0 \r\n con el que se finaliza
            la transferencia de archivos*/
            scan_buf = 0;
            should_end = 1;
            printf("Termine de recibir la totalidad del archivo\n");
        }

        else if (num == 0 && (sep_index - h) > 0){
            /*Si estoy aca, estoy viendo el 0 OK de cuando el cliente me
            responde que recibio el get_slice correctamente*/
            h = sep_index + 2;
            /*Me posiciono despues del \r\n*/
            q = h;
            sep_index = binstr(received,q,sep);
            if (sep_index == -1){
                scan_buf = 0;
            }
            #ifdef __DEBUG__
            printf("Recibi respuesta OK del servidor, creo el archivo.\n\
en caso de ya existir, lo trunco a 0\n");
            #endif
            /*Creo el archivo*/
            aux = calloc (strlen(TEMP_FOLDER) + strlen(filename)+2,\
                sizeof(char*));
            if (aux == NULL){
                /*Hubo error*/
                bcstrfree(file_temp);
                file_temp = NULL;
                free(aux_buf);
                aux_buf=NULL;
                return -1;
            }
            strcpy (aux,TEMP_FOLDER);
            strncat (aux, filename, strlen(filename));
            if ((f = fopen (aux,"w")) == NULL) {
                /*en caso de error liberamos todo y retornamos*/
                free(aux);
                aux = NULL;
                bcstrfree(file_temp);
                file_temp = NULL;
                free(aux_buf);
                aux_buf=NULL;
                return -1;
            }
            free(aux);
            aux = NULL;

            if (fclose(f) != 0){
                /*hubo error*/
                bcstrfree(file_temp);
                file_temp = NULL;
                free(aux_buf);
                aux_buf=NULL;
                return -1;
            }

        }
        else{
            if (num > (sep_index - h)){
                /*Si entro a este if, entonces encontre un \r\n en el payload
                lo ignoro y busco el siguiente*/
                sep_index = binstr(received, (sep_index+2),sep);
                if (sep_index == -1){
                    /*Si no encuentro un \r\n salgo del bucle para poder
                    recibir mas*/
                    scan_buf = 0;
                }
            }
            else{
                /*si entro aca es porque encontre el \r\n donde deberia estar,
                tomo el payload y lo guardo en el archivo temporal*/
                p=0;
                payload=calloc(num, sizeof(char));
                while (p<num){
                    payload[p] = file_temp[h];
                    h++;
                    p++;
                }
                h++;
                h++;
                q = h;

                /*en aux voy a guardar el nombre de la carpeta temporal
                concatenado con el nombre del archivo*/
                aux = calloc (strlen(TEMP_FOLDER) + strlen(filename)+2,\
                    sizeof(char*));
                if (aux == NULL){
                    /*Hubo error*/
                    bcstrfree(file_temp);
                    file_temp = NULL;
                    free(aux_buf);
                    aux_buf=NULL;
                    return -1;
                }
                strcpy (aux,TEMP_FOLDER);
                strncat (aux, filename, strlen(filename));
                if ((f = fopen (aux,"ab")) == NULL) {
                    /*en caso de error liberamos todo y retornamos*/
                    free(aux);
                    aux = NULL;
                    bcstrfree(file_temp);
                    file_temp = NULL;
                    free(aux_buf);
                    aux_buf=NULL;
                    return -1;
                }
                free(aux);
                aux = NULL;
                /*En este momento tengo el archivo abierto, debo
                escribir el payload*/
    
                if ((fwrite(payload, 1, (size_t)num, f)) < (size_t)num){
                    /*ha ocurrido un error*/
                    bcstrfree(file_temp);
                    file_temp = NULL;
                    free(aux_buf);
                    aux_buf=NULL;
                    return -1;
                }
                free(payload);
                payload=NULL;
                if (fclose(f) != 0){
                    /*hubo error*/
                    bcstrfree(file_temp);
                    file_temp = NULL;
                    free(aux_buf);
                    aux_buf=NULL;
                    return -1;
                }
                /*Actualizo el valor de cuanto llevo transferido
                hasta el momento*/
                fd_list_server_set_transferred(list, i, transferred+num);
                sep_index = binstr(received,q,sep);
                if (sep_index == -1){
                    scan_buf = 0;
                }
            }
        }
    }

    /*Ahora me fijo si llegue aca porque termine de recibir o si tengo que
    seguir recibiendo*/

    if (!(should_end || scan_buf)){
        /*Tengo que buscar mas datos, cargo lo que tengo por el momento
        en la estructura*/
        not_loaded = (received->slen) - (q);
        p=0;
        payload=calloc(not_loaded, sizeof(char));
        while (p<not_loaded){
            payload[p] = file_temp[q];
            q++;
            p++;
        }

        bdestroy(received);
        received = blk2bstr(payload, p);
        free(payload);
        payload=NULL;
    }

    if (should_end){
        should_end=0;
        /*Una vez que termine de recibir el archivo, lo muevo
        a la carpeta definitiva*/
        aux_old = calloc (strlen(TEMP_FOLDER) + strlen(filename)+2,\
                    sizeof(char*));
        aux_new = calloc (strlen(FOLDER) + strlen(filename)+2,\
                    sizeof(char*));
        strcpy (aux_old,TEMP_FOLDER);
        strncat (aux_old, filename, strlen(filename));
        strcpy (aux_new,FOLDER);
        strncat (aux_new, filename, strlen(filename));
        rename(aux_old, aux_new);
        fd_list_set_server_recv(list, i, true);
        fd_list_server_clear_file(list, i);
        free(aux_old);
        aux_old=NULL;
        free(aux_new);
        aux_new=NULL;

        bdestroy(sep);
        bdestroy(received);

        bcstrfree(file_temp);
        file_temp = NULL;
        free(aux_buf);
        aux_buf=NULL;
        return 1;
    }
    else{
        /*Si entro aca, entonces cargo en la estructura lo que tengo por el
        momento para seguir manejandolo despues*/
        fd_list_server_clear_file(list, i);
        fd_list_server_set_file(list, i, received);
    }

    bdestroy(sep);
    bdestroy(received);

    bcstrfree(file_temp);
    file_temp = NULL;
    free(aux_buf);
    aux_buf=NULL;
    return 0;
}

void configure_new_file(fd_list list, int i){
    bool flag;

    flag = fd_list_server_get_new_file(list, i);
    fd_list_server_clear_new_file(list);
    if (flag){
        fd_list_server_set_new_file(list, i);
    }
    fd_list_server_stop_receiving(list, i);
    fd_list_server_send(list, i);
    fd_list_set_server_cmd(list, i, 1);

}

int attend_new_file(fd_list list, int i){
    int fd_server=0, fd_client=0, j=0;

    /*Entramos aqui porque un cliente nos informo que tiene archivos nuevos
    luego, buscamos el fd relacionado (servidor) y aguardamos hasta que su 
    lista de archivos se haya vaciado, es entonces cuando le damos la señal
    para que vaya a pedir el nuevo archivo al servidor*/

    fd_client = fd_list_get_fd(list, i);
    /*Primero le respondo 0 OK*/
    send_msg(fd_client, MSG0);

    fd_server = fd_list_item_get_relation(list, i);
    j = fd_list_server_search(list, fd_server);
    if (j!=-1){
        /*Levanto el flag para que cuando termine empiece de nuevo*/
        fd_list_server_set_start_over(list, j);

        /*configuramos al cliente como que ya finalizó*/
        fd_list_set_finish(list, i, true);
        return 1;
    }
    else{
        /*Si entro aqui es porque el fd no se encontro en la lista de servidores
        algo no anda bien*/
        #ifdef __DEBUG__
        printf("ERROR: No se encontro el fd en la lista de servidores\n");
        #endif
        /*configuramos al cliente como que ya finalizó*/
        fd_list_set_finish(list, i, true);
        return -1;
    }
}
